using System;
using System.Collections.Generic;
using System.Linq;
using Firestarter.DB.Schema.BO;
using Firestarter.DM_DB.Logic;
using FireStarterModeller.BO;
using FireStarterModeller.Test;
using Habanero.Base;
using NUnit.Framework;
using Rhino.Mocks;

namespace Firestarter.DB_DM.Logic.Test
{
    [TestFixture]
    public class TestDBFactory : TestBase
    {
        internal static DBFactory CreateDBFactory()
        {
            IDMTypeToDBColumnTypeMapper typeMapper = MockRepository.GenerateStub<IDMTypeToDBColumnTypeMapper>();
            return new DBFactory(typeMapper);
        }

        [Test]
        public void Test_Construct()
        {
            //---------------Set up test pack-------------------
            IDMTypeToDBColumnTypeMapper typeMapper = MockRepository.GenerateStub<IDMTypeToDBColumnTypeMapper>();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            DBFactory factory = new DBFactory(typeMapper);
            //---------------Test Result -----------------------
            Assert.IsNotNull(factory);
            Assert.AreSame(typeMapper, factory.DMTypeToDBColumnTypeMapper);
        }

        [Test]
        public void Test_Construct_WhenNullDBTypeToDMPropertyTypeMapper_ShouldThrowError()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                DBFactory factory = new DBFactory(null);
                //---------------Test Result -----------------------
                Assert.Fail("Expected to throw an ArgumentNullException");
            }
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("typeMapper", ex.ParamName);
            }
        }

        [Test]
        public void Test_CreateDBDatabase()
        {
            //---------------Set up test pack-------------------
            List<DMClass> dmclasses = CreateDMClassesWithRelationshipBetween(Cardinality.Single, Cardinality.Single);
            DBFactory factory = CreateDBFactory();

            //---------------Execute Test ----------------------
            DBDatabase database = factory.CreateDBDatabase(dmclasses.Cast<IClassDef>());
            //---------------Test Result -----------------------
            Assert.AreEqual(2, database.Tables.Count);
            Assert.AreEqual(dmclasses[0].MappedTableName, database.Tables[0].TableName);
            Assert.AreEqual(dmclasses[1].MappedTableName, database.Tables[1].TableName);
            Assert.AreEqual(1, database.Tables[0].ForeignKeys.Count);
            Assert.AreEqual(0, database.Tables[1].ForeignKeys.Count);
        }


        public static List<DMClass> CreateDMClassesWithRelationshipBetween(Cardinality cardinality, Cardinality relatedCardinality)
        {
            DMClass relatedClass;
            DMClass @class;
            DMProperty dmProperty = null;
            DMProperty relatedProperty = null;
            if (relatedCardinality == Cardinality.Multiple)
            {
                @class = TestUtilsDMClass.CreateSavedDMClassWithOID(0);
                dmProperty = @class.Properties[0];
            } else {
                @class = TestUtilsDMClass.CreateUnsavedValidDMClass();
                dmProperty = TestUtilsShared.CreateUnsavedValidDMProperty(@class);
            }

            if (relatedCardinality == Cardinality.Single) {
                relatedClass = TestUtilsDMClass.CreateSavedDMClassWithOID(0);
                relatedProperty = relatedClass.Properties[0];
            } else {
                relatedClass = TestUtilsDMClass.CreateUnsavedValidDMClass();
                relatedProperty = TestUtilsShared.CreateUnsavedValidDMProperty(relatedClass);
            }
            DMRelationship relationship = @class.RelatedRelationships.CreateBusinessObject();
            relationship.RelatedClass = relatedClass;
            relationship.RelationshipName = TestUtilsShared.GetRandomString();
            relationship.Cardinality = cardinality;
            relationship.ReverseRelationship.Cardinality = relatedCardinality;
            relationship.ReverseRelationship.RelationshipName = TestUtilsShared.GetRandomString();
            DMRelationshipProperty relProp = relationship.RelationshipProperties.CreateBusinessObject();
            relProp.OwnerProperty = dmProperty;
           
            relProp.RelatedProperty = relatedProperty;
            return new List<DMClass>() { @class, relatedClass };
        }
    }
}